<?php

if (!function_exists('wechatLogin')) {

    function wechatLogin($code)
    {
        $appid = env('WX_SALES_APP_ID');
        $secret = env('WX_SALES_APP_SECRET');
        $url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' . $appid . '&secret=' . $secret . '&js_code=' . $code . '&grant_type=authorization_code';
        $result = connectWeChat($url);
        $resultArr = json_decode($result, true);
        if (isset($resultArr['errcode'])) {
            switch ($resultArr['errcode']) {
                case -1:
                    $resultArr['errmsg'] = '系统繁忙, 请稍后再试';
                    break;
                case 40029:
                    $resultArr['errmsg'] = 'code 无效';
                    break;
                case 45011:
                    $resultArr['errmsg'] = '频率限制，每个用户每分钟100次';
                    break;
                case 40163:
                    $resultArr['errmsg'] = 'code 已经被使用';
                    break;
            }
        }

        return $resultArr;
    }

    /**
     * 订单关闭api
     * params:
     * 商户订单号: out_trade_no
     */
    function orderClose($data)
    {
        //小程序就是小程序的appid
        $appid = env('WX_SALES_APP_ID');
        //微信商户id
        $mch_id = env('WX_SALES_MCH_ID');
        //微信商户key
        $key = env('WX_SALES_MCH_SECRET');
        //随机字符串
        $nonce_str = md5(uniqid(microtime(true), true));
        //商户订单号, 唯一, 暂时先用时间错
        $out_trade_no = date('YmdHis');
        $body = '订单标题';

        $post['appid'] = $appid;
        $post['mch_id'] = $mch_id;
        $post['nonce_str'] = $nonce_str;
        $post['out_trade_no'] = $out_trade_no;
        //签名
        $sign = makeSign($post, $key);

        $post_xml = '<xml>
               <appid>' . $appid . '</appid>
               <body>' . $body . '</body>
               <mch_id>' . $mch_id . '</mch_id>
               <nonce_str>' . $nonce_str . '</nonce_str>
               <out_trade_no>' . $out_trade_no . '</out_trade_no>
               <sign>' . $sign . '</sign>
            </xml> ';

        //订单关闭接口 POST方式请求
        $url = 'https://api.mch.weixin.qq.com/pay/closeorder';
        $xml = http_request($url, $post_xml);

        //将【统一下单】api返回xml数据转换成数组，全要大写
        $array = xmlToArray($xml);
        $result = [];
        if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
            //订单关闭成功, 需要处理订单的状态
            $result['RETURN_CODE'] = $array['RETURN_CODE'];
            $result['RESULT_CODE'] = $array['RESULT_CODE'];

        } else {
            $result['RETURN_CODE'] = $array['RETURN_CODE'];
            $result['RETURN_MSG'] = $array['RETURN_MSG'];
        }

        return $result;
    }

    /**
     * 统一下单api
     * params:
     * 付款金额:total_fe,必须为整数, 单位为分
     * 付款说明: body
     */
    function wechatPrepay($data)
    {
        //小程序就是小程序的appid
        $appid = env('WX_SALES_APP_ID');
        //微信商户id
        $mch_id = env('WX_SALES_MCH_ID');
        //微信商户key
        $key = env('WX_SALES_MCH_SECRET');
        //支付完成回调地址url,不能带参数
        $notify_url = env('WX_SALES_NOTIFY_URL');
        //随机字符串
        $nonce_str = md5(uniqid(microtime(true), true));
        //商户订单号, 唯一, 暂时先用时间错
        $out_trade_no = date('YmdHis');
        //客服端ip
        $spbill_create_ip = $_SERVER['SERVER_ADDR'];
        //交易类型 为 NATIVE 时, 返回付款二维码链接 code_url
        $trade_type = 'NATIVE';
        //微信用户id, 当交易类型为 JSAPI 时, open_id 为必填
        //$openid = $data['open_id'];
        //订单费用, 单位 分,必须是整数
        $total_fee = 1;
        $body = '全普医学检验';

        $post['appid'] = $appid;
        $post['body'] = $body;
        $post['mch_id'] = $mch_id;
        $post['nonce_str'] = $nonce_str;
        $post['notify_url'] = $notify_url;
        //$post['openid'] = $openid;
        $post['out_trade_no'] = $out_trade_no;
        $post['spbill_create_ip'] = $spbill_create_ip;
        $post['total_fee'] = intval($total_fee);
        $post['trade_type'] = $trade_type;
        //签名
        $sign = makeSign($post, $key);

        $post_xml = '<xml>
               <appid>' . $appid . '</appid>
               <body>' . $body . '</body>
               <mch_id>' . $mch_id . '</mch_id>
               <nonce_str>' . $nonce_str . '</nonce_str>
               <notify_url>' . $notify_url . '</notify_url>
               <out_trade_no>' . $out_trade_no . '</out_trade_no>
               <spbill_create_ip>' . $spbill_create_ip . '</spbill_create_ip>
               <total_fee>' . $total_fee . '</total_fee>
               <trade_type>' . $trade_type . '</trade_type>
               <sign>' . $sign . '</sign>
            </xml> ';

        //统一下单接口prepay_id, POST方式请求
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = http_request($url, $post_xml);

        //将【统一下单】api返回xml数据转换成数组，全要大写
        $array = xmlToArray($xml);
        $result = [];
        if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
            $result['CODE_URL'] = $array['CODE_URL'];
            $result['RETURN_CODE'] = $array['RETURN_CODE'];
            $result['RESULT_CODE'] = $array['RESULT_CODE'];

            /*// JSAPI 支付, 需要二次签名唤起支付
            $time = time();
            $tmp = [];                            //临时数组用于签名
            $tmp['appId'] = $appid;
            $tmp['nonceStr'] = $nonce_str;
            $tmp['package'] = 'prepay_id=' . $array['PREPAY_ID'];
            $tmp['signType'] = 'MD5';
            $tmp['timeStamp'] = $time;

            $data['state'] = 1;
            $data['timeStamp'] = $time;           //时间戳
            $data['nonceStr'] = $nonce_str;         //随机字符串
            $data['signType'] = 'MD5';              //签名算法，暂支持 MD5
            $data['package'] = 'prepay_id=' . $array['PREPAY_ID'];   //统一下单接口返回的 prepay_id 参数值，提交格式如：prepay_id=*
            $data['paySign'] = $this->MakeSign($tmp, $key);
            $data['out_trade_no'] = $out_trade_no;*/

        } else {
            $result['RETURN_CODE'] = $array['RETURN_CODE'];
            $result['RETURN_MSG'] = $array['RETURN_MSG'];
        }

        return $result;
    }

    /**
     * 支付成功回调
     * @param Request $request
     * @return array
     */
    function notify()
    {
        try {
            $receiveXml = file_get_contents("php://input");
            $bodyArray = xmlToArray($receiveXml);   //微信支付成功，返回回调地址url的数据：XML转数组Array
            $postSign = $bodyArray['sign'];
			//去除签名,对返回的数据进行二次签名
            unset($bodyArray['sign']);

            //鉴权，保证安全
            $signArray = [
                'appid' => $bodyArray['APPID'] ?? null,
                'bank_type' => $bodyArray['BANK_TYPE'] ?? null,
                'cash_fee' => $bodyArray['CASH_FEE'] ?? null,
                'fee_type' => $bodyArray['FEE_TYPE'] ?? null,
                'is_subscribe' => $bodyArray['IS_SUBSCRIBE'] ?? null,
                'mch_id' => $bodyArray['MCH_ID'] ?? null,
                'nonce_str' => $bodyArray['NONCE_STR'] ?? null,
                'openid' => $bodyArray['OPENID'] ?? null,
                'out_trade_no' => $bodyArray['OUT_TRADE_NO'] ?? null,
                'result_code' => $bodyArray['RESULT_CODE'] ?? null,
                'return_code' => $bodyArray['RETURN_CODE'] ?? null,
                'time_end' => $bodyArray['TIME_END'] ?? null,
                'total_fee' => $bodyArray['TOTAL_FEE'] ?? null,
                'trade_type' => $bodyArray['TRADE_TYPE'] ?? null,
                'transaction_id' => $bodyArray['TRANSACTION_ID'] ?? null,
            ];

            //微信商户key
            $key = env('WX_SALES_MCH_SECRET');
            //重新生成签名
            $newSign = makeSign($signArray, $key);

            if (!(isset($bodyArray['SIGN']) && $bodyArray['SIGN'] == $newSign)) {
                return null;
            }

            if (isset($bodyArray['RETURN_CODE']) && $bodyArray['RETURN_CODE'] == 'SUCCESS' &&
                isset($bodyArray['RESULT_CODE']) && $bodyArray['RESULT_CODE'] == 'SUCCESS') {
                //支付成功
            }else{
                //记录错误信息
            }

            //返回确认信信息
            $return['return_code'] = 'SUCCESS';
            $return['return_msg'] = 'OK';
            $returnXml = '<xml>
                    <return_code>' . $return['return_code'] . '</return_code>
                    <return_msg>' . $return['return_msg'] . '</return_msg>
                    </xml>';
            return $returnXml;

        } catch (\Exception $e) {
            return $this->throwError($e);
        }
    }

    function makeSign($params, $key)
    {
        //签名步骤一：按字典序排序数组参数
        ksort($params);
        $string = toUrlParams($params);  //参数进行拼接key=value&k=v
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . $key;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     * 将参数拼接为url: key=value&key=value
     * @param $params
     * @return string
     */
    function toUrlParams($params)
    {
        $string = '';
        if (!empty($params)) {
            $array = array();
            foreach ($params as $key => $value) {
                $array[] = $key . '=' . $value;
            }
            $string = implode("&", $array);
        }
        return $string;
    }

    /**
     * 调用接口， $data是数组参数
     * @return 签名
     */
    function http_request($url, $data = null, $headers = array())
    {
        $curl = curl_init();
        if (count($headers) >= 1) {
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    //获取xml里面数据，转换成array
    function xmlToArray($xml)
    {
        $p = xml_parser_create();
        xml_parse_into_struct($p, $xml, $vals, $index);
        xml_parser_free($p);
        $data = [];
        foreach ($index as $key => $value) {
            if ($key == 'xml' || $key == 'XML') continue;
            $tag = $vals[$value[0]]['tag'];
            $value = $vals[$value[0]]['value'];
            $data[$tag] = $value;
            //将键值转化为小写
            //$data[strtolower($tag)] = $value;
        }

        return $data;
    }

    function connectWeChat($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 6);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

}